package base.jdk8_demo.lambda.demo07;

import base.jdk8_demo.lambda.demo02.Status;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.junit.Before;
import org.junit.Test;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Stream 练习
 */
public class TestStreamDemo {
    List<Emp> emps = Arrays.asList(
            new Emp(100,"zs",16,1000.0, Status.VACATION),
            new Emp(101,"ls", 38, 3000.0, Status.FREE),
            new Emp(102,"ww", 17, 2000.0, Status.VACATION),
            new Emp(103,"zl", 39, 4000.0, Status.FREE),
            new Emp(104,"dg", 60, 5000.0, Status.BUSY),
            new Emp(105,"tom", 61, 6000.0, Status.BUSY)
        );
    /**
     * 给定一个数字列表，返回一个由每个数字的平方构成的列表
     */
    @Test
    public void testCase1(){
        Integer[] nums = new Integer[]{1,3,5,7,9};
        Arrays.stream(nums)
                .map(num -> num * num)
                .forEach(System.out::println);
    }

    /**
     * 用 map-reduce 统计流中有多少Emp对象
     */
    @Test
    public void testCase2(){
        Optional<Integer> op = emps.stream()
                .map(emp -> 1)
//                .reduce(Integer::sum);
                .reduce((i1,i2) -> i1+i2);
        System.out.println("总人数: "+op.get());
        
        Integer count = emps.stream()
        	.map(emp -> 1)
        	.reduce(0, (x,y) -> x+y);
        System.out.println("总人数: "+ count);
        
        IntSummaryStatistics iss = emps.stream()
        	.collect(Collectors.summarizingInt(e -> e.getAge()));
        System.out.println("总人数: "+ iss.getCount());
        System.out.println("平均年龄: "+iss.getAverage());
    }

    List<Transaction> transactions = null;
    @Before
    public void init(){
        Trader Tom = new Trader("Tom", "Milan");
        Trader Cat = new Trader("Cat", "Moscow");
        Trader Amy = new Trader("Amy", "Paris");
        Trader Jerry = new Trader("Jerry", "Moscow");

        transactions = Arrays.asList(
                new Transaction(Tom, 2020, 200),
                new Transaction(Cat, 2021, 100),
                new Transaction(Cat, 2020, 500),
                new Transaction(Amy, 2020, 600),
                new Transaction(Amy, 2021, 200),
                new Transaction(Jerry, 2021, 150)
        );
    }

    /**
     * 找出2020年发生所有交易，并按交易额排序（从低到高）
     */
    @Test
    public void testCase3(){
//        Stream<Transaction> transactionStream = transactions.stream();
//        transactionStream = transactionStream.filter(t -> t.getYear() == 2020);// 过滤之后还是Transaction 流
//        transactionStream = transactionStream.sorted((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()));// 排序时拿到的是流中的每个Transaction，因此我们要通过getValue()拿到交易额进行排序
//        transactionStream.forEach(System.out::println);
        transactions.stream()
        			.filter(t -> t.getYear() == 2020)
        			.sorted((t1, t2) -> t1.getValue().compareTo(t2.getValue()))//升序
        			.forEach(System.out::println);
    }
    /**
     * 交易员都在哪些不同的城市工作过
     */
    @Test
    public void testCase4(){
        Stream<Transaction> transactionStream = transactions.stream();
        Stream<String> stringStream = transactionStream.map(t -> t.getTrader().getCity());
        stringStream = stringStream.distinct();
        stringStream.forEach(System.out::println);
    }
    /**
     * 查找所有来自 Moscow 的交易员，并按姓名排序
     */
    @Test
    public void testCase5(){
//        Stream<Trader> traderStream =
        Stream<Transaction> transactionStream = transactions.stream();
        transactionStream = transactionStream.filter(t -> t.getTrader().getCity().equals("Moscow"));
//        Stream<Trader> traderStream = transactionStream.map(Transaction::getTrader);//实现
        Stream<Trader> traderStream = transactionStream.map(t -> t.getTrader());
        traderStream = traderStream.sorted((t1, t2) -> t1.getName().compareTo(t2.getName()));
        traderStream = traderStream.distinct();
        traderStream.forEach(System.out::println);
    }
    /**
     * 返回所有交易员的姓名，并按字母顺序排序
     */
    @Test
    public void testCase6(){
        Stream<Transaction> transactionStream = transactions.stream();
        Stream<String> stringStream = transactionStream.map(t -> t.getTrader().getName())
                                                        .distinct();
        stringStream = stringStream.sorted((n1, n2) -> n1.compareTo(n2));
        stringStream.forEach(System.out::println);
    }
    /**
     * 有没有交易员是在 Paris 工作的
     */
    @Test
    public void testCase7(){
        Stream<Transaction> transactionStream = transactions.stream();
        boolean isParis = transactionStream.anyMatch(t -> t.getTrader().getCity().equals("Paris"));
        System.out.println("有在 Paris 工作的交易员吗？"+isParis);
    }
    /**
     * 打印所有在 Moscow 的交易员的所有交易总额
     */
    @Test
    public void testCase8(){
        // 方式一
        Stream<Transaction> transactionStream = transactions.stream();
        transactionStream = transactionStream.filter(t -> t.getTrader().getCity().equals("Moscow"));
        Stream<Integer> integerStream = transactionStream.map(Transaction::getValue);
        Optional<Integer> optional = integerStream.reduce(Integer::sum);
        System.out.println("交易总额："+optional.get());

        // 方式二
        LongSummaryStatistics summaryStatistics = transactions.stream()
                .filter(t -> t.getTrader().getCity().equals("Moscow"))
                //.map(Transaction::getValue)
                .collect(Collectors.summarizingLong(Transaction::getValue));
        System.out.println("人数："+ summaryStatistics.getCount());
        System.out.println("交易总额："+ summaryStatistics.getSum());
    }
    /**
     * 所有的交易中，最高的交易额是多少
     */
    @Test
    public void testCase9(){
        // 方式一
        Stream<Transaction> transactionStream = transactions.stream();
        Stream<Integer> integerStream = transactionStream.map(t -> t.getValue());
//        Optional<Integer> max = integerStream.max(Integer::compareTo);
        Optional<Integer> max = integerStream.max((x,y) -> x-y);
        System.out.println("最高交易额是："+max.get());

        // 方式二
        Transaction transaction = transactions.stream()
                .collect(Collectors.maxBy((t1, t2) -> t1.getValue() - t2.getValue()))
                .get();
        System.out.println("最高交易额是："+transaction.getValue());
    }
    /**
     * 找到交易额最小的交易
     */
    @Test
    public void testCase10(){
        Stream<Transaction> transactionStream = transactions.stream();
//        Optional<Transaction> min = transactionStream.min((t1, t2) -> t1.getValue().compareTo(t2.getValue()));
        // 或者
        Optional<Transaction> min = transactionStream.min((t1, t2) -> Integer.compare(t1.getValue(), t2.getValue()));
        System.out.println("最小交易："+min.get());
    }

}

@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
class Emp {
    private Integer id;
    private String name;
    private Integer age;
    private Double salary;
    private Status status;
}

@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
class Trader{
    private String name;
    private String city;
}

@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
class Transaction{
    private Trader trader;
    private Integer year;
    private Integer value;
}
